package com.dm.cloud.images.util;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.async.ResultCallback;
import com.github.dockerjava.api.command.*;
import com.github.dockerjava.api.exception.*;
import com.github.dockerjava.api.model.*;
import com.github.dockerjava.core.DockerClientBuilder;
import com.github.dockerjava.httpclient5.ApacheDockerHttpClient;
import com.dm.cloud.core.exception.CustomException;
import com.dm.cloud.core.util.ApplicationUtil;
import com.dm.cloud.images.mode.*;

import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.Instant;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import static java.lang.String.format;

public class DockerUtil {

    private static String LOAD_SUCCESS_PREFIX="Loaded image:";

    /**
     * 获取docker 客户端
     * @param host
     * @param port
     * @return
     */
    public static DockerClient get(String host,int port){
        ApacheDockerHttpClient httpClient = null;
        try {
            httpClient = new ApacheDockerHttpClient.Builder()
                    .dockerHost(new URI(format("tcp://%s:%d", host, port)))
                    .build();

        } catch (URISyntaxException e) {
            throw new CustomException("容器节点配置错误！");
        }
        DockerClient client = DockerClientBuilder
                .getInstance()
                .withDockerHttpClient(httpClient)
                .build();
        return client;
    }
//      -------------------------------- 镜像--------------------------------------------
    /**
     * 加载镜像
     * @param client
     * @param in
     * @return
     * @throws CustomException
     */
    public static String loadImage(DockerClient client, InputStream in) throws CustomException{
        LoadImageCallback callbak = client.loadImageAsyncCmd(in).start();
        String img=null;
        try {
            img = callbak.awaitMessage();
        }catch (DockerClientException e){
            e.printStackTrace();
            String msg=e.getMessage();
            if(msg!=null){
                if(msg.contains("Could not build image")){
                    throw new CustomException("镜像加载失败,请检查镜像,必须使用镜像tag打包！");
                }
            }
            throw new CustomException("镜像加载失败，请检查镜像是否可用！");
        }

        if(StrUtil.isNotEmpty(img) && img.trim().startsWith(LOAD_SUCCESS_PREFIX)){
            return img.replace(LOAD_SUCCESS_PREFIX,"").trim();
        }else{
            throw new CustomException("镜像上传失败!"+img);
        }
    }

    /**
     * 删除镜像
     * @param client 节点
     * @param imageName 镜像名称
     * @param force 是否删除关联镜像 强制移除正在运行的容器（使用 SIGKILL）
     */
    public static void deleteImage(DockerClient client, String imageName,boolean force) {
        try {
            client.removeImageCmd(imageName).withForce(force).exec();
        } catch (NotFoundException e) {
            throw new CustomException("镜像不存在！"+imageName);
        } catch (Exception e){
            e.printStackTrace();
            throw new CustomException("镜像删除失败！"+imageName);
        }
    }


//      -------------------------------- 网络--------------------------------------------
    public static Network  createnetwork(DockerClient client, NetworkCreatMode creatMode){

//        参数说明：
//        --attachable：启用手动容器附加。
//        --aux-address map：网络驱动程序使用的辅助IPv4或IPv6地址（默认为map[]）。
//        --config-from string：从中复制配置的网络。
//        --config-only：仅创建配置网络。
//        -d, --driver string：管理网络的驱动程序（默认为bridge）。
//        --gateway strings：主子网的IPv4或IPv6网关。
//        --ingress：创建Swarm路由网格网络。
//        --internal：限制对网络的外部访问。
//        --ip-range strings：从子范围中分配容器IP。
//        --ipam-driver string：IP地址管理驱动程序（默认为default）。
//        --ipam-opt map：设置IPAM驱动程序的特定选项（默认为map[]）。
//        --ipv6：启用IPv6网络。
//        --label list：在网络上设置元数据。
//        -o, --opt map：设置特定驱动程序的选项（默认为map[]）。
//        --scope string：控制网络的范围。
//        --subnet strings：以CIDR格式表示的子网，表示网络段。



        try {
            //创建网络
            CreateNetworkCmd createNetworkCmd = client.createNetworkCmd();
            if(creatMode.getAttachable()!=null){
                // 这个网络是否可以被其它容器使用，默认true.false的其它容器用不了
                createNetworkCmd.withAttachable(creatMode.getAttachable());
            }
            if(creatMode.getCheckDuplicate()!=null){
                //重复检查
                createNetworkCmd.withCheckDuplicate(creatMode.getCheckDuplicate());
            }
            if(StrUtil.isNotEmpty(creatMode.getDriver())){
                //驱动类型：
                //    bridge：这是Docker的默认网络驱动，用于创建一个桥接网络。容器可以通过这个网络与其他容器和宿主机进行通信。
                //    host：这个驱动用于创建一个网络，该网络与宿主机的网络命名空间共享。这意味着容器可以使用宿主机的网络接口和配置。
                //    none：这个驱动用于创建一个没有网络配置的网络。容器不会有任何网络接口，除了lo（本地回环）。
                //    container：这个驱动用于创建一个网络，该网络连接到另一个正在运行的容器。这允许容器之间进行网络通信，但它们不会与宿主机或其他容器共享网络。
                //    macvlan：这个驱动用于创建一个基于macvlan的局域网。这允许容器之间进行网络通信，并且可以与宿主机和其他容器共享网络。
                //    overlay：这个驱动用于创建一个基于VXLAN的覆盖网络，用于在不同主机上的容器之间进行网络通信。
                //    network：这个驱动用于创建一个自定义网络，它允许你使用Docker的网络插件来定义网络配置。
                //    ThirdParty：这个驱动用于创建一个第三方网络，这允许你使用第三方网络解决方案来管理网络。
                createNetworkCmd.withDriver(creatMode.getDriver());
            }

            if(creatMode.getInternal()!=null){
                createNetworkCmd.withInternal(creatMode.getInternal());  //限制外部访问网络
            }

            if(ObjectUtil.isNotEmpty(creatMode.getIpam())){
                createNetworkCmd.withIpam(creatMode.getIpam());

                //            Map<String,String> ipamOptions=new HashMap<>();  //设置IPAM驱动程序的特定选项。 暂时不知道怎么用
//            Network.Ipam ipam = new Network.Ipam()
////        驱动类型:
////        default：这是Docker的默认IPAM驱动，它适用于大多数网络类型，并提供了基本的IP地址管理功能。
////        dhcp：这个驱动用于在网络中启用DHCP服务器，以自动分配IP地址给连接到该网络的容器。
////        fixed：这个驱动用于为网络中的容器分配固定的IP地址。你可以通过--ipam-driver=fixed参数与--ip-range参数一起使用，来指定IP地址的范围。
////        random：这个驱动用于为网络中的容器分配随机的IP地址。这在你想要避免使用固定IP地址，或者没有特定IP地址要求时很有用。
////        Ginny：这是Docker的实验性IPAM驱动，它旨在提供更好的IP地址管理功能，包括支持自定义的IP地址分配策略。
//                    .withDriver("default")
//                    .withConfig(new Network.Ipam.Config()
//                            //网段 172.28.1.0/24  /24表示子网掩码为255.255.255.0，即这个子网中只有256个IP地址，其中一个是默认网关地址172.28.1.1，剩下的是可用地址。
//                            .withSubnet("172.28.1.0/24")
//                            //网关
//                            .withGateway("172.20.1.1")
//                            // 网络地址从172.20.10.0 - 172.20.10.255   /24表示子网掩码为255.255.255.0，即这个子网中只有256个IP地址。
//                            .withIpRange("172.20.1.15/24")
//                    );
////            ipam.getOptions().putAll(ipamOptions); //此处报错

            }

            if(ObjectUtil.isNotEmpty(creatMode.getLabels())){
                createNetworkCmd.withLabels(creatMode.getLabels()); //标签
            }

            if(creatMode.getEnableIpv6()!=null){
                createNetworkCmd.withEnableIpv6(creatMode.getEnableIpv6());// 打开ipv6
            }

            if(StrUtil.isEmpty(creatMode.getName())){
                throw new CustomException("网络名称不能为空!");
            }
            createNetworkCmd.withName(creatMode.getName());

            if(ObjectUtil.isNotEmpty(creatMode.getOpt())){
                //        --opt com.docker.network.bridge.name=xxx：指定网络桥接的名称。这是Docker网络的一个默认值，但您可以通过这个选项来修改它。
                //        --opt com.docker.network.bridge.enable_icc=true：指定是否启用桥接网络中的容器间通信（icc）。默认情况下，这个选项是启用的。
                //        --opt com.docker.network.bridge.enable_ip_masquerading=true：指定是否启用IP伪装。这通常用于容器之间的通信，使得容器可以像普通的主机一样进行通信。
                //        --opt com.docker.network.bridge.enable_userland_proxy=true：指定是否启用用户代理。这通常用于容器访问外部网络时，通过Docker守护进程进行代理。
                //        --opt com.docker.network.bridge.enable_mtu=true：指定是否启用MTU（最大传输单元）检测。这有助于确保网络中的MTU设置不会导致通信问题。
                //        --opt com.docker.network.bridge.enable_ip_forwarding=true：指定是否启用IP转发。这对于网络中的容器访问外部网络是非常重要的。
                //        --opt com.docker.network.bridge.enable_packet NSMutableDictionary=true：指定是否启用数据包级联。这通常用于高级网络配置，例如负载均衡。
                //        --opt com.docker.network.bridge.enable_seckill=true：指定是否启用网络抢占。这通常用于网络故障转移场景。
                //        --opt com.docker.network.bridge.enableBinding.UIManager=true：指定是否启用绑定用户界面。这有助于在容器启动时显示网络相关的用户界面。
                //        --opt com.docker.network.bridge.enablehairpin_mode=true：指定是否启用hairpin模式。这有助于解决某些网络配置中的循环依赖问题。
                //        --opt com.docker.network.bridge.default_bridge: 这个选项指定是否创建一个默认的网络桥接。在Docker中，默认的桥接网络通常命名为docker0。将这个选项设置为true意味着如果您没有指定其他网络驱动，Docker将创建一个默认的桥接网络。
                //        --opt com.docker.network.bridge.enable_icc: 这个选项指定是否启用容器间通信（icc）。当设置为true时，容器可以相互通信，就像它们连接到同一个网络交换机上一样。这是Docker网络的默认行为。
                //        --opt com.docker.network.bridge.enable_ip_masquerade: 这个选项指定是否启用IP伪装。当设置为true时，Docker将为容器分配一个虚拟的IPv4地址，并允许容器通过Docker守护进程进行网络通信，就像它们直接连接到物理网络交换机上一样。
                //        --opt com.docker.network.bridge.host_binding_ipv4: 这个选项指定Docker守护进程监听的IPv4地址。设置为0.0.0.0意味着Docker将监听所有接口上的连接请求，而不绑定到特定的IPv4地址。
                //        --opt com.docker.network.bridge.name: 这个选项指定网络桥接的名称。在这里，它被设置为docker0，这是Docker默认的桥接网络名称。
                //        --opt com.docker.network.driver.mtu: 这个选项指定网络的最大传输单元（MTU）。在这里，它被设置为1500，这是一个常见的以太网MTU值。MTU是网络上的最大数据包大小，这个值需要根据您的网络环境和需求来设置。
                creatMode.setOpt(creatMode.getOpt());
            }
            CreateNetworkResponse networkResponse = createNetworkCmd.exec();
            String networkId = networkResponse.getId();
            Network network = client.inspectNetworkCmd().withNetworkId(networkId).exec();
            return network;
        }catch (ConflictException e){
            e.printStackTrace();
            if(e.getMessage().contains("already exists")){
                throw new CustomException("网络创建失败,网络已存在!");
            }else {
                throw new CustomException("网络创建失败!"+e.getMessage());
            }
        }catch (Exception e){
            e.printStackTrace();
            throw new CustomException("网络创建失败!"+e.getMessage());
        }
    }

    /**
     * 删除网络
     * @param dockerClient
     * @param networkId
     * @return
     */
    public static boolean deleteNetwork(DockerClient dockerClient, String networkId){
        try {
            Network network = dockerClient.inspectNetworkCmd().withNetworkId(networkId).exec();
            if(MapUtil.isNotEmpty(network.getContainers())){
                List<String> containerNames = network.getContainers().values().stream().map((n) -> n.getName()).collect(Collectors.toList());
                throw new CustomException("网络已被容器["+String.join(",",containerNames)+"]使用");
            }
        }catch (Exception e){
            if(e instanceof CustomException){
                throw e;
            }else {
                throw new CustomException("获取网络信息错误！");
            }
        }
        try {
            dockerClient.removeNetworkCmd(networkId).exec();
        }catch (Exception e) {
            throw new CustomException("网络删除失败!" + e.getMessage());
        }
        return true;
    }

    public static List<Network> listNetwork(DockerClient client,String name){
        ListNetworksCmd cmd = client.listNetworksCmd();
        if(StrUtil.isNotEmpty(name)){
            cmd.withFilter("name", Arrays.asList(name));
        }
        try {
            List<Network> networks = cmd.exec();
            return networks;
        }catch (Exception e){
            e.printStackTrace();
            throw new CustomException("网络列表查询错误！");
        }

    }

//      -------------------------------- 数据卷--------------------------------------------
    /**
     * 创建数据卷
     * @param dockerClient
     * @param volumeCreateRequest
     * @return
     */
    public static InspectVolumeResponse createVolumes(DockerClient dockerClient, VolumeCreateRequest volumeCreateRequest) {
        CreateVolumeCmd createVolumeCmd = dockerClient.createVolumeCmd()
                .withDriver(volumeCreateRequest.getDriver())
                .withName(volumeCreateRequest.getName());
        //nfs数据卷
        if(volumeCreateRequest.getEnableNfs()!=null && volumeCreateRequest.getEnableNfs()){
            Map<String,String> opt=new HashMap<>();
            opt.put("type","nfs");
            opt.put("o","addr="+volumeCreateRequest.getNfsServer()+",rw"); //rw代表有读写权限
            opt.put("device",volumeCreateRequest.getDevice());
            createVolumeCmd.withDriverOpts(opt);
        }
        try {
            CreateVolumeResponse resp = createVolumeCmd.exec();
            return dockerClient.inspectVolumeCmd(resp.getName()).exec();
        }catch (Exception e){
            e.printStackTrace();
            throw new CustomException("数据卷创建失败!");
        }
    }

    /**
     * 查询数据卷列表
     * @param dockerClient
     * @param name
     * @return
     */
    public static List<InspectVolumeResponse> volumesList(DockerClient dockerClient, String name){
        ListVolumesCmd cmd = dockerClient.listVolumesCmd();
        if(StrUtil.isNotEmpty(name)){
            cmd.withFilter("name", Arrays.asList(name));
        }
        try {
            ListVolumesResponse resp = cmd.exec();
            return resp.getVolumes();
        }catch (Exception e){
            e.printStackTrace();
            throw new CustomException("查询失败!"+e.getMessage());
        }
    }

    /**
     * 删除数据卷
     * @param client
     * @param name
     * @return
     */
    public static boolean deleteVolume(DockerClient client,String name){
        try {
            client.removeVolumeCmd(name).exec();
            return true;
        }catch (Exception e){
            e.printStackTrace();
            throw new CustomException("删除数据卷失败！");
        }
    }

//      -------------------------------- 容器-----------------------------------------
    /**
     * 查询容器列表
     * @param client
     * @param name
     * @return
     */
    public static List<Container> listContainer(DockerClient client, String name){
        ListContainersCmd cmd = client
                .listContainersCmd()
                .withShowAll(true);
//                .withShowSize(true);  //打开这个会导致查询速度非常慢
        if(StrUtil.isNotEmpty(name)){
            cmd.withFilter("name",Arrays.asList(name));
        }
        try {
            List<Container> containers = cmd.exec();
            return containers;
        }catch (Exception e){
            throw new CustomException("容器查询失败!"+e.getMessage());
        }
    }

    /**
     * 创建容器
     * @param client
     * @param creatMode
     * @return
     */
    public static Container createContainer(DockerClient client, ContainerCreateMode creatMode) {
        RepositoryUtils repository = ApplicationUtil.getBean(RepositoryUtils.class);
        String image= repository.repositoryImage(creatMode.getImage_name(),creatMode.getTag_name());
        checkOrPullImage(client,image);
        CreateContainerCmd cmd = client.createContainerCmd(image);
//        cmd.withAuthConfig(repository.harborAuth()); //配置仓库链接关系
        //容器用户
        if(StrUtil.isNotEmpty(creatMode.getUser())){
            cmd.withUser(creatMode.getUser());
        }
        cmd.withName(creatMode.getContainerName());
        if(StrUtil.isNotEmpty(creatMode.getAlias())){
            cmd.withAliases(creatMode.getAlias());
        }

        // -i
        if(creatMode.getInteractive()!=null){
            cmd.withStdInOnce(creatMode.getInteractive());
        }

        // -t
        if(creatMode.getTty()!=null){
            cmd.withTty(creatMode.getTty());
        }

        //cmd
        if(creatMode.getCmd()!=null && !creatMode.getCmd().isEmpty()){
            cmd.withCmd(creatMode.getCmd());
        }

        HostConfig hostConfig = HostConfig.newHostConfig();

        // -v
        if(creatMode.getVolumes()!=null && !creatMode.getVolumes().isEmpty()){
            List<Bind> binds=new ArrayList<>();
            List<Mount> mounts=new ArrayList<>();
            creatMode.getVolumes().forEach((key,value)->{
//                if(value.startsWith(CommonProp.SHARD_VOLUME_PREFIX)){
//                    binds.add(Bind.parse(key+":"+value.substring(CommonProp.SHARD_VOLUME_PREFIX.length())));
//                }else{
//                    volumes.add(new Volume(value));
//                    new Bind(key, new Volume(value));
//                }
                if(key.startsWith("/")){
                    binds.add(Bind.parse(key+":"+value));
                }else{
//                    binds.add(new Bind(value,new Volume(key)));
                    //绑定已有的数据卷
                    mounts.add(new Mount().withSource("my-existing-volume").withTarget("/path/to/container/directory").withType(MountType.VOLUME));
                }
            });
//            cmd.withVolumes(volumes);
            hostConfig.withBinds(binds);
            hostConfig.withMounts(mounts);
        }

        //重启策略
        if(StrUtil.isNotEmpty(creatMode.getRestartPolicy())){
            hostConfig.withRestartPolicy(RestartPolicy.parse(creatMode.getRestartPolicy()));
        }
        // -p
        if(creatMode.getPortBound()!=null && !creatMode.getPortBound().isEmpty()){
            List<ExposedPort > exposedPorts=new ArrayList<>();
            List<PortBinding> portBindings = new ArrayList<>();
            creatMode.getPortBound().forEach((host,container)->{
                ExposedPort containerPort = ExposedPort.parse(container.toString());
                exposedPorts.add(containerPort);
                portBindings.add(PortBinding.parse(host+":"+container));
            });
            hostConfig.withPortBindings(portBindings);
            cmd.withExposedPorts(exposedPorts);
        }
        // --add-host 指定域名  xxxx:192.168.0.1
        if(creatMode.getExtraHosts()!=null && !creatMode.getExtraHosts().isEmpty()){
            List<String> extraHosts=new ArrayList<>();
            creatMode.getExtraHosts().forEach((host,ip)->{
                extraHosts.add(host+":"+ip);
            });
            hostConfig.withExtraHosts(extraHosts.toArray(new String[extraHosts.size()]));
        }
        // --privileged 是否有主机权限
        if(creatMode.getPrivileged()!=null && creatMode.getPrivileged()){
            hostConfig.withPrivileged(creatMode.getPrivileged());
        }

        // -e
        if(creatMode.getEnvGroup()!=null && !creatMode.getEnvGroup().isEmpty()){
            List<String> envGroup=new ArrayList<>();
            creatMode.getEnvGroup().forEach((key,value)->{
                envGroup.add(key+"="+value);
            });
            cmd.withEnv(envGroup);
        }
        // dns
        if(StrUtil.isNotEmpty(creatMode.getDns())){
            hostConfig.withDns(creatMode.getDns());
        }

        // -n 网络
        if(StrUtil.isNotEmpty(creatMode.getNetwork())){
            hostConfig.withNetworkMode(creatMode.getNetwork());
        }
        cmd.withHostConfig(hostConfig);
        try {
            CreateContainerResponse rep = cmd.exec();
            return findContainerById(client,rep.getId());
        }catch (DockerException e){
            e.printStackTrace();
            int httpStatus = e.getHttpStatus();
            if(httpStatus==400){
                throw new CustomException("参数错误！"+e.getMessage());
            }else if(httpStatus==404){
                throw new CustomException("镜像不存在！"+e.getMessage());
            }else if(httpStatus==409){
                throw new CustomException("容器冲突！"+e.getMessage());
            }else{
                throw new CustomException("容器服务错误！"+e.getMessage());
            }
        }catch (Exception e){
            throw new CustomException("容器服务错误！"+e.getMessage());
        }
    }

    /**
     * 启动容器
     * @param id
     * @return
     */
    public static Container startContainer(DockerClient client,String id) {
        try {
            client.startContainerCmd(id).exec();
            return findContainerById(client,id);
        }catch (DockerException e){
            int httpStatus = e.getHttpStatus();
            if(httpStatus==304){
                throw new CustomException("容器已经是启动的！");
            }else if(httpStatus==404){
                throw new CustomException("容器不存在！"+e.getMessage());
            }else{
                throw new CustomException("容器服务错误！"+e.getMessage());
            }
        }catch (Exception e){
            e.printStackTrace();
            throw new CustomException("容器服务错误！"+e.getMessage());
        }

    }

    private static Container findContainerById(DockerClient client,String id){
        List<Container> containers = client.listContainersCmd().withShowAll(true).withIdFilter(Arrays.asList(id)).exec();
        if(containers!=null && containers.size()>0){
            return containers.get(0);  //返回第一个
        }else{
            return null;
        }
    }

    private static long isoTime(String dateStr){
        DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
        ZonedDateTime dateTime = ZonedDateTime.parse(dateStr, formatter);
        Instant instant = dateTime.toInstant(); // 将ZonedDateTime转换为Instant
        Date date = Date.from(instant); // 使用Instant创建java.util.Date对象
        return date.getTime();
    }

    private static void checkOrPullImage(DockerClient client,String imagesName){

        try {
            InspectImageResponse inspectImageResponse = client.inspectImageCmd(imagesName).exec();
            return ;
        }catch (Exception e){
            e.printStackTrace();
            //镜像不存在!
        }
        RepositoryUtils repository = ApplicationUtil.getBean(RepositoryUtils.class);
        try {
            ResultCallback.Adapter<PullResponseItem> pull = client.pullImageCmd(imagesName)
                    .withAuthConfig(repository.harborAuth()).start();
            ResultCallback.Adapter<PullResponseItem> s = pull.awaitCompletion();
        } catch (InternalServerErrorException e) {
            e.printStackTrace();
            if(e.getMessage()!=null && e.getMessage().matches("Status 500: unknown: repository .*? not found")){
                throw new CustomException("镜像不存在！");
            }else{
                throw new CustomException("镜像拉取失败!");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            throw new CustomException("镜像拉取错误!");
        }
    }

    /**
     * 关闭容器
     * @param client
     * @param id
     * @return
     */
    public static Container stopContainer(DockerClient client, String id) {
        try {
            client.stopContainerCmd(id).exec();
            return findContainerById(client,id);
        }catch (DockerException e){
            int httpStatus = e.getHttpStatus();
            if(httpStatus==304){
                throw new CustomException("容器已经是停止的！");
            }else if(httpStatus==404){
                throw new CustomException("容器不存在！"+e.getMessage());
            }else{
                throw new CustomException("容器服务错误！"+e.getMessage());
            }
        }catch (Exception e){
            e.printStackTrace();
            throw new CustomException("容器服务错误！"+e.getMessage());
        }
    }

    /**
     * 重启容器
     * @param client
     * @param id
     * @return
     */
    public static Container restartContainer(DockerClient client, String id) {
        try {
            client.restartContainerCmd(id).exec();
            return findContainerById(client,id);
        }catch (DockerException e){
            int httpStatus = e.getHttpStatus();
            if(httpStatus==404){
                throw new CustomException("容器不存在！"+e.getMessage());
            }else{
                throw new CustomException("容器服务错误！"+e.getMessage());
            }
        }catch (Exception e){
            e.printStackTrace();
            throw new CustomException("容器服务错误！"+e.getMessage());
        }
    }

    /**
     * 关闭容器
     * @param client
     * @param id
     * @return
     */
    public static Boolean killContainer(DockerClient client, String id) {
        try {
            client.killContainerCmd(id).withSignal("KILL-C").exec();
            return true;
        }catch (DockerException e){
            int httpStatus = e.getHttpStatus();
            if(httpStatus==404){
                throw new CustomException("容器不存在！"+e.getMessage());
            }else if(httpStatus==409){
                throw new CustomException("容器未运行！"+e.getMessage());
            }else{
                throw new CustomException("容器服务错误！"+e.getMessage());
            }
        }catch (Exception e){
            e.printStackTrace();
            throw new CustomException("容器服务错误！"+e.getMessage());
        }
    }

    /**
     * 强制删除容器
     * @param client
     * @param id
     * @param delV 是否删除关联数据卷
     * @return
     */
    public static Boolean deleteContainer(DockerClient client, String id,Boolean delV) {
        try {
            delV=delV==null?false:delV;
            client.removeContainerCmd(id)
                    .withRemoveVolumes(delV)
                    .withForce(true) //默认删除之前关闭
                    .exec();
            return true;
        }catch (DockerException e){
            int httpStatus = e.getHttpStatus();
            if(httpStatus==400){
                throw new CustomException("参数错误！"+e.getMessage());
            }else if(httpStatus==404){
                throw new CustomException("容器不存在！"+e.getMessage());
            }else if(httpStatus==409){
                throw new CustomException("容器操作存在冲突！"+e.getMessage());
            }else{
                throw new CustomException("容器服务错误！"+e.getMessage());
            }
        }catch (Exception e){
            e.printStackTrace();
            throw new CustomException("容器服务错误！"+e.getMessage());
        }
    }

    /**
     * 容器详情
     * @param client
     * @param containerID
     * @return
     */
    public static Container containerDetail(DockerClient client, String containerID) {
        return findContainerById(client,containerID);
    }



//      -------------------------------- 节点 -----------------------------------------
    /**
     *  ping 节点
     * @return
     */
    public static Boolean pingNode(DockerClient client) {
        try {
            client.pingCmd().exec();
            return true;
        }catch (Exception e){
            return false;
        }
    }

    /**
     * 节点详情
     * @param client
     * @return
     */
    public static Info nodeInfo(DockerClient client){
        return client.infoCmd().exec();
    }

}
